from threading import Thread
import time
from datetime import datetime, timedelta
from FlowViewer import Listener

from common.web.Base import Chrome, Action
from common.logger.log import log_
from autoTask.operaitonAid.pinduoduo.spiderFont import PddFont
from autoTask.operaitonAid.utils.request_data import requests_data


class Task(Chrome):
    storeName: str

    def __init__(self):
        super().__init__()
        page = self.page
        self.this = self.init_this()
        self.listener = Listener(self.port)
        self.exit_app = 1

    def run(self):
        page = self.page
        page.get('https://mms.pinduoduo.com/home/')
        self.storeName = page.ele('x://div[@class="user-name-name"]/span[@class="user-name-text"]').text
        try:
            Thread_listen = Thread(target=self.TaskListen)
            Thread_listen.start()
            time.sleep(2)
            self.Query()
            Thread_listen.join()
        except Exception as e:
            self.stop(e)
        if self.exit_app:
            raise Exception('子线程错误')

    @staticmethod
    def init_this():
        return {
            'font_map': {},
            'dataList': []
        }

    def TaskListen(self):
        """监听子线程"""
        listener = self.listener
        listener.listen(['.ttf', 'queryGoodsDetailVOListForMMS', 'web/en/ft'], asyn=True)
        for response in listener.steps():
            body = response.body
            if response.target == '.ttf':
                log_.debug('TTF handle')
                Thread(target=self.spiderFont, args=(body, )).start()
            elif response.target == 'queryGoodsDetailVOListForMMS':
                log_.debug('data')
                if not isinstance(body, dict):
                    raise Exception(f'Response <{body}> Type Error')
                self.this['dataList'].extend(body['result']['goodsDetailList'])
        self.exit_app = 0

    def stop(self, errMsg=None):
        """关闭监听子线程"""
        self.listener.stop()
        if errMsg:
            raise Exception(errMsg)

    def Query(self):
        """主线程"""
        self.this = self.init_this()
        self.get_detail()
        map_length = len(self.this['font_map'])
        if map_length % 10 != 0:
            self.get_detail(1)
        self.analysis()
        self.stop()

    def analysis(self):
        """字体解密并提取保存"""
        font_handle = PddFont()
        font_handle.dbMap = self.this['font_map']
        atob = font_handle.atob
        DetailList = self.this['dataList']
        for detail in DetailList:
            detail_info = {
                "dataCycle": self.get_cycle(detail['statDate']),  # 数据日期
                "storeName": self.storeName,  # 店铺名称
                "productName": detail['goodsName'],  # 商品名称
                "productId": detail['goodsId'],  # 商品id
                "categoryName": detail['cate3Name'],  # 类目名称
                "productVisitorNums": atob(detail['goodsUv']),  # 商品访客数
                "productBrowseNums": atob(detail['goodsPv']),  # 商品浏览量
                "paymentNums": atob(detail['payOrdrGoodsQty']),  # 支付件数
                "paymentBuyerNums": atob(detail['payOrdrUsrCnt']),  # 支付买家数
                "paymentOrderNums": atob(detail['payOrdrCnt']),  # 支付订单数
                "transactionAmount": atob(detail['payOrdrAmt']),  # 交易金额
                "orderNumberOfPeople": atob(detail['ordrCrtUsrCnt']),  # 下单人数
                "paymentConversionRate": atob(detail['goodsVcr']),  # 支付转化率
                "placeOrderRate": atob(detail['ordrVstrRto']),  # 下单率
                "payoutRate": atob(detail['payOrdrRto']),  # 支付率
                "productCollectionNums": atob(detail['goodsFavCnt']),  # 商品收藏用户数
                "numberOfGroupOrders": atob(detail['cfmOrdrCnt']),  # 成团订单数
                "productGroupNums": atob(detail['cfmOrdrGoodsQty']),  # 商品成团件数
                "productHelpPlatformRate": atob(detail['goodsPtHelpRate'])  # 商品求助平台率
            }
            detail_info['uvValue'] = self.float_compute(detail_info['transactionAmount'], detail_info['productVisitorNums'])  # UV价值
            detail_info['customerUnitPrice'] = self.float_compute(detail_info['transactionAmount'], detail_info['paymentBuyerNums'])  # 客单价
            detail_info['collectionRate'] = self.float_compute(detail_info['productCollectionNums'], detail_info['productVisitorNums'], 100)   # 收藏率
            response = requests_data("post", uri="public/details/commit", params=detail_info, req_title='拼多多商品明细')
            if response.get('code') == 0:
                log_.info(f'{detail["goodsName"]} {detail_info["dataCycle"]}已保存')

    @staticmethod
    def float_compute(val1, val2, percentage=1):
        """
        计算 取整 保留后两位
        :param val1: 除数
        :param val2: 被除数
        :param percentage: 1 or 100, 1为结果已经是百分比, 100则不是
        :return: 计算结果
        """
        val1 = float(val1)
        val2 = float(val2)
        if not val1 or not val2:
            return 0 if percentage == 1 else 0.00
        return round(float(val1) / float(val2) * percentage, 2)

    @staticmethod
    def get_cycle(this: str) -> str:
        """
        保存日期格式
        :param this: 当前日期: YYYY-MM-DD
        :return: YYYY-MM-DD~YYYY-MM-DD
        """
        date_format = '%Y-%m-%d'
        date_time = datetime.strptime(this, date_format)
        future_time = date_time - timedelta(days=29)
        result = f'{future_time.strftime(date_format)}~{this}'
        return result

    def get_detail(self, tries=0):
        """获取详细信息"""
        if tries > 1:
            self.stop('字体错误 重试一次仍无法解决')
            return
        page = self.page
        url = 'https://mms.pinduoduo.com/sycm/goods_effect/detail?dateFlag=2'
        page.get(url)
        self.next_page()

    def next_page(self):
        """点击下一页"""
        page = self.page
        disable_next = page.ele('x://li[@class="PGT_next_5-47-0 PGT_disabled_5-47-0"]', timeout=2)
        if disable_next:
            time.sleep(4)
            return
        next_btn = page.ele('x://li[@data-testid="beast-core-pagination-next"]', timeout=3)
        if not next_btn:
            return
        next_btn.click()
        time.sleep(4)
        self.next_page()

    def spiderFont(self, content):
        if not content:
            raise Exception('字体文件获取失败')
        font_handle = PddFont()
        font_handle.ttf_save(content)
        font_handle.dbMap = {}
        font_handle.comparison()
        self.this['font_map'].update(font_handle.dbMap)


if __name__ == '__main__':
    Task().run()
